<{extend name="Public:public" /}>

<{block name="title"}>组件基础<{/block}>

<{block name="content"}> 
<div class="content guide with-sidebar components-guide">
    <h1>组件基础</h1>
  
  
    <h2 id="基本示例">
			<a href="#基本示例" class="headerlink" title="基本示例" data-scroll="">基本示例</a>
		</h2>
		<blockquote>
			<div>van: 组件name的作用</div>
		</blockquote>
		<ol>
			<li><keep-alive> exclude="组件名"</li>
			<li>递归组件</li>
			<li>vue-detools 调试中</li>
		</ol>
		
		<p>这里有一个 Vue 组件的示例：</p>
<figure class="highlight js"><table><tbody><tr><td class="code"><pre><span class="line"><span class="comment">// 定义一个名为 button-counter 的新组件</span></span><br><span class="line">Vue.component(<span class="string">'button-counter'</span>, {</span><br><span class="line">  data: <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>{</span><br><span class="line">    <span class="keyword">return</span> {</span><br><span class="line">      count: <span class="number">0</span></span><br><span class="line">    }</span><br><span class="line">  },</span><br><span class="line">  template: <span class="string">'&lt;button v-on:click="count++"&gt;You clicked me {{ count }} times.&lt;/button&gt;'</span></span><br><span class="line">})</span><br></pre></td></tr></tbody></table></figure>
<p>组件是可复用的 Vue 实例，且带有一个名字：在这个例子中是 <code>&lt;button-counter&gt;</code>。我们可以在一个通过 <code>new Vue</code> 创建的 Vue 根实例中，把这个组件作为自定义元素来使用：</p>
<figure class="highlight html"><table><tbody><tr><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">id</span>=<span class="string">"components-demo"</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">button-counter</span>&gt;</span><span class="tag">&lt;/<span class="name">button-counter</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br></pre></td></tr></tbody></table></figure>
<figure class="highlight js"><table><tbody><tr><td class="code"><pre><span class="line"><span class="keyword">new</span> Vue({ <span class="attr">el</span>: <span class="string">'#components-demo'</span> })</span><br></pre></td></tr></tbody></table></figure>

<div id="components-demo" class="demo"><button>You clicked me 0 times.</button></div>
<script>
Vue.component('button-counter', {
  data: function () {
    return {
      count: 0
    }
  },
  template: '<button v-on:click="count += 1">You clicked me {{ count }} times.</button>'
})
new Vue({ el: '#components-demo' })
</script>

<p>因为组件是可复用的 Vue 实例，所以它们与 <code>new Vue</code> 接收相同的选项，例如 <code>data</code>、<code>computed</code>、<code>watch</code>、<code>methods</code> 以及生命周期钩子等。仅有的例外是像 <code>el</code> 这样根实例特有的选项。</p>
<h2 id="组件的复用"><a href="#组件的复用" class="headerlink" title="组件的复用" data-scroll="">组件的复用</a></h2><p>你可以将组件进行任意次数的复用：</p>
<figure class="highlight html"><table><tbody><tr><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">id</span>=<span class="string">"components-demo"</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">button-counter</span>&gt;</span><span class="tag">&lt;/<span class="name">button-counter</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">button-counter</span>&gt;</span><span class="tag">&lt;/<span class="name">button-counter</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">button-counter</span>&gt;</span><span class="tag">&lt;/<span class="name">button-counter</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br></pre></td></tr></tbody></table></figure>

<div id="components-demo2" class="demo"><button>You clicked me 0 times.</button> <button>You clicked me 0 times.</button> <button>You clicked me 0 times.</button></div>
<script>
new Vue({ el: '#components-demo2' })
</script>

<p>注意当点击按钮时，每个组件都会各自独立维护它的 <code>count</code>。因为你每用一次组件，就会有一个它的新<strong>实例</strong>被创建。</p>
<h3 id="data-必须是一个函数"><a href="#data-必须是一个函数" class="headerlink" title="data 必须是一个函数" data-scroll=""><code>data</code> 必须是一个函数</a></h3><p>当我们定义这个 <code>&lt;button-counter&gt;</code> 组件时，你可能会发现它的 <code>data</code> 并不是像这样直接提供一个对象：</p>
<figure class="highlight js"><table><tbody><tr><td class="code"><pre><span class="line">data: {</span><br><span class="line">  count: <span class="number">0</span></span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure>
<p>取而代之的是，<strong>一个组件的 <code>data</code> 选项必须是一个函数</strong>，因此每个实例可以维护一份被返回对象的独立的拷贝：</p>
<figure class="highlight js"><table><tbody><tr><td class="code"><pre><span class="line">data: <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>{</span><br><span class="line">  <span class="keyword">return</span> {</span><br><span class="line">    count: <span class="number">0</span></span><br><span class="line">  }</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure>
<p>如果 Vue 没有这条规则，点击一个按钮就可能会像如下代码一样影响到<em>其它所有实例</em>：</p>

<div id="components-demo3" class="demo"><button>You clicked me 0 times.</button> <button>You clicked me 0 times.</button> <button>You clicked me 0 times.</button></div>
<script>
var buttonCounter2Data = {
  count: 0
}
Vue.component('button-counter2', {
  data: function () {
    return buttonCounter2Data
  },
  template: '<button v-on:click="count++">You clicked me {{ count }} times.</button>'
})
new Vue({ el: '#components-demo3' })
</script>

<h2 id="组件的组织"><a href="#组件的组织" class="headerlink" title="组件的组织" data-scroll="">组件的组织</a></h2><p>通常一个应用会以一棵嵌套的组件树的形式来组织：</p>
<p><img src="/images/components.png" alt="Component Tree"></p>
<p>例如，你可能会有页头、侧边栏、内容区等组件，每个组件又包含了其它的像导航链接、博文之类的组件。</p>
<p>为了能在模板中使用，这些组件必须先注册以便 Vue 能够识别。这里有两种组件的注册类型：<strong>全局注册</strong>和<strong>局部注册</strong>。至此，我们的组件都只是通过 <code>Vue.component</code> 全局注册的：</p>
<figure class="highlight js"><table><tbody><tr><td class="code"><pre><span class="line">Vue.component(<span class="string">'my-component-name'</span>, {</span><br><span class="line">  <span class="comment">// ... options ...</span></span><br><span class="line">})</span><br></pre></td></tr></tbody></table></figure>
<p>全局注册的组件可以用在其被注册之后的任何 (通过 <code>new Vue</code>) 新创建的 Vue 根实例，也包括其组件树中的所有子组件的模板中。</p>
<p>到目前为止，关于组件注册你需要了解的就这些了，如果你阅读完本页内容并掌握了它的内容，我们会推荐你再回来把<a href="components-registration.html">组件注册</a>读完。</p>



<h2 id="单个根元素"> 
	<a href="#单个根元素" class="headerlink" title="单个根元素" data-scroll="">单个根元素</a> 
</h2> 
<p>当构建一个 <code>&lt;blog-post&gt;</code> 组件时，你的模板最终会包含的东西远不止一个标题：</p>
<figure class="highlight html"><table><tbody><tr><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">h3</span>&gt;</span>{{ title }}<span class="tag">&lt;/<span class="name">h3</span>&gt;</span></span><br></pre></td></tr></tbody></table></figure>
<p>最最起码，你会包含这篇博文的正文：</p>
<figure class="highlight html"><table><tbody><tr><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">h3</span>&gt;</span>{{ title }}<span class="tag">&lt;/<span class="name">h3</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">v-html</span>=<span class="string">"content"</span>&gt;</span><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br></pre></td></tr></tbody></table></figure>
<p>然而如果你在模板中尝试这样写，Vue 会显示一个错误，并解释道 <strong>every component must have a single root element (每个组件必须只有一个根元素)</strong>。你可以将模板的内容包裹在一个父元素内，来修复这个问题，例如：</p>
<figure class="highlight html"><table><tbody><tr><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"blog-post"</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">h3</span>&gt;</span>{{ title }}<span class="tag">&lt;/<span class="name">h3</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">div</span> <span class="attr">v-html</span>=<span class="string">"content"</span>&gt;</span><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br></pre></td></tr></tbody></table></figure>
<p>看起来当组件变得越来越复杂的时候，我们的博文不只需要标题和内容，还需要发布日期、评论等等。为每个相关的信息定义一个 prop 会变得很麻烦：</p>
<figure class="highlight html"><table><tbody><tr><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">blog-post</span></span></span><br><span class="line"><span class="tag">  <span class="attr">v-for</span>=<span class="string">"post in posts"</span></span></span><br><span class="line"><span class="tag">  <span class="attr">v-bind:key</span>=<span class="string">"post.id"</span></span></span><br><span class="line"><span class="tag">  <span class="attr">v-bind:title</span>=<span class="string">"post.title"</span></span></span><br><span class="line"><span class="tag">  <span class="attr">v-bind:content</span>=<span class="string">"post.content"</span></span></span><br><span class="line"><span class="tag">  <span class="attr">v-bind:publishedAt</span>=<span class="string">"post.publishedAt"</span></span></span><br><span class="line"><span class="tag">  <span class="attr">v-bind:comments</span>=<span class="string">"post.comments"</span></span></span><br><span class="line"><span class="tag">&gt;</span><span class="tag">&lt;/<span class="name">blog-post</span>&gt;</span></span><br></pre></td></tr></tbody></table></figure>
<p>所以是时候重构一下这个 <code>&lt;blog-post&gt;</code> 组件了，让它变成接受一个单独的 <code>post</code> prop：</p>
<figure class="highlight html"><table><tbody><tr><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">blog-post</span></span></span><br><span class="line"><span class="tag">  <span class="attr">v-for</span>=<span class="string">"post in posts"</span></span></span><br><span class="line"><span class="tag">  <span class="attr">v-bind:key</span>=<span class="string">"post.id"</span></span></span><br><span class="line"><span class="tag">  <span class="attr">v-bind:post</span>=<span class="string">"post"</span></span></span><br><span class="line"><span class="tag">&gt;</span><span class="tag">&lt;/<span class="name">blog-post</span>&gt;</span></span><br></pre></td></tr></tbody></table></figure>
<figure class="highlight js"><table><tbody><tr><td class="code"><pre><span class="line">Vue.component(<span class="string">'blog-post'</span>, {</span><br><span class="line">  props: [<span class="string">'post'</span>],</span><br><span class="line">  template: <span class="string">`</span></span><br><span class="line"><span class="string">    &lt;div class="blog-post"&gt;</span></span><br><span class="line"><span class="string">      &lt;h3&gt;{{ post.title }}&lt;/h3&gt;</span></span><br><span class="line"><span class="string">      &lt;div v-html="post.content"&gt;&lt;/div&gt;</span></span><br><span class="line"><span class="string">    &lt;/div&gt;</span></span><br><span class="line"><span class="string">  `</span></span><br><span class="line">})</span><br></pre></td></tr></tbody></table></figure>
<p class="tip">上述的这个和一些接下来的示例使用了 JavaScript 的<a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Template_literals" target="_blank" rel="noopener">模板字符串</a>来让多行的模板更易读。它们在 IE 下并没有被支持，所以如果你需要在不 (经过 Babel 或 TypeScript 之类的工具) 编译的情况下支持 IE，请使用<a href="https://css-tricks.com/snippets/javascript/multiline-string-variables-in-javascript/" target="_blank" rel="noopener">折行转义字符</a>取而代之。</p>

<p>现在，不论何时为 <code>post</code> 对象添加一个新的属性，它都会自动地在 <code>&lt;blog-post&gt;</code> 内可用。</p>


  
  
  
</div>
<{/block}>
